/**
 * 
 */
package bsh;

import org.objectweb.asm.MethodVisitor;

import bsh.asm.acessor.ObjectAccessor;
import bsh.meta.MethodDescriptor;
import bsh.meta.TypeWrapper;

/**
 * {@link ObjectAccessor} that uses getter and setter to get/set 'fields'
 * 
 * @author takeshi
 */
public class BeanPropertyObjectAccessor implements ObjectAccessor {

    private final MethodDescriptor getter, setter;

    private final DynamicFieldObjectAccessor dynamicAccessor;

    /**
     * C'tor
     * 
     * @param getter the getter {@link MethodDescriptor}
     * @param setter the setter {@link MethodDescriptor}
     */
    public BeanPropertyObjectAccessor(MethodDescriptor getter, MethodDescriptor setter) {
        this(getter, setter, null);
    }

    /**
     * C'tor
     * 
     * @param getter the getter {@link MethodDescriptor}
     * @param fieldName the name of the field
     */
    public BeanPropertyObjectAccessor(MethodDescriptor getter, String fieldName) {
        this(getter, null, new DynamicFieldObjectAccessor(fieldName));
    }

    /**
     * C'tor
     * 
     * @param getter the getter {@link MethodDescriptor}
     * @param setter the setter {@link MethodDescriptor}
     * @param dynamicAccessor the {@link DynamicFieldObjectAccessor}
     */
    private BeanPropertyObjectAccessor(MethodDescriptor getter, MethodDescriptor setter, DynamicFieldObjectAccessor dynamicAccessor) {
        super();
        this.getter = getter;
        this.setter = setter;
        this.dynamicAccessor = dynamicAccessor;
    }

    /**
     * {@inheritDoc}
     */
    public void loadObject(MethodVisitor visitor, CompilationState state) {
        state.assertMinimumStackSize(1);
        getter.writeInvoke(visitor, state);
    }

    /**
     * {@inheritDoc}
     */
    public void preStore(MethodVisitor visitor, CompilationState state) {
        if (setter == null) {
            dynamicAccessor.preStore(visitor, state);
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean readOnly() {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public void storeObject(MethodVisitor visitor, CompilationState state) {
        if (setter == null) {
            dynamicAccessor.storeObject(visitor, state);
        } else {
            setter.writeInvoke(visitor, state);
        }
    }

    /**
     * {@inheritDoc}
     */
    public TypeWrapper type() {
        return getter.returnType();
    }

}